package com.xinziruo.crawl.infrastruture.support.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Random;
import java.util.concurrent.Executors;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

import com.xinziruo.crawl.infrastruture.support.codec.CommandProtocolDecoder;
import com.xinziruo.crawl.infrastruture.support.codec.CommandProtocolEncoder;
import com.xinziruo.crawl.infrastruture.support.command.Command;
import com.xinziruo.crawl.infrastruture.support.filter.CommandClientInjectFilter;

/**
 * 
 * @author loudyn
 *
 */
public class CommandServerBroker {

	/**
	 * 
	 * @param port
	 * @throws IOException
	 */
	public CommandServerBroker(int port) throws IOException {
		
		NioSocketAcceptor acceptor = new NioSocketAcceptor();
		DefaultIoFilterChainBuilder fcBuilder = acceptor.getFilterChain();
		fcBuilder.addLast("command-codec-filter", new ProtocolCodecFilter(new CommandProtocolEncoder(), new CommandProtocolDecoder()));
		fcBuilder.addLast("client-inject-filter", new CommandClientInjectFilter());
		fcBuilder.addLast(
							"executor", 
							new ExecutorFilter(Executors.newFixedThreadPool(30))
				);

		acceptor.setHandler(new CommandProtocolHandler());
		acceptor.bind(new InetSocketAddress(port));
	}

	/**
	 * 
	 * @author loudyn
	 * 
	 */
	@SuppressWarnings("serial")
	public static class NoneCommandClientException extends RuntimeException {

		public NoneCommandClientException(String message) {
			super(message);
		}

	}

	/**
	 * 
	 * @param comm
	 */
	public void broadcastCommand(Command comm) throws Exception {
		CommandClient[] clients = CommandClientHolder.clientsSnapshotAsArray();
		for (CommandClient client : clients) {
			client.writeCommand(comm);
		}
	}

	/**
	 * 
	 * @param comm
	 */
	public void writeCommand(Command comm) throws Exception {
		CommandClient client = selectClientByRandom();
		client.writeCommand(comm);
	}

	private CommandClient selectClientByRandom() {
		CommandClient[] clients = CommandClientHolder.clientsSnapshotAsArray();
		if (clients.length <= 0) {
			throw new NoneCommandClientException("There are none commandClient!");
		}

		int random = createRandom(clients.length);
		return clients[random];
	}

	private int createRandom(int length) {
		Random random = new Random();
		return random.nextInt(length);
	}
}
